#include "common.h"
#include "counter.h"
#include "Vsoc.h"
#include "difftest.h"
#define TRACE 0
#define TRACE_BEGIN_TIME 0
#define MAX_WAVE 100000
#define MAX_CYCLE 2000000000ull
Vsoc *top;
VerilatedFstC *tfp;
static uint64_t wave_cnt = 0;

bool percent(int change)
{
    uint32_t r = rand();
    r %= 100;
    return r < change;
}
void dump()
{
#if TRACE
    if (Verilated::time() < TRACE_BEGIN_TIME)
        return;
    if (wave_cnt < MAX_WAVE)
    {
        tfp->dump(Verilated::time());
        wave_cnt++;
    }
#endif
}

void run()
{
    top->eval();
    dump();
    Verilated::timeInc(1);

    top->clk = 0;
    top->eval();
    dump();
    Verilated::timeInc(2);

    top->clk = 1;
    top->eval();
    dump();
    Verilated::timeInc(1);
}
void reset()
{
    LOG("reset");
    top->rst = 1;
    run();
    run();
    run();
    top->rst = 0;
}
Counter cycle("cycle");
extern Counter total_inst;
extern uint64_t lastCommitTime;
void soc_test()
{
    LOG("soc_test");
    reset();
    do
    {
        run();
        cycle++;
        Assert(Verilated::time() - lastCommitTime < 1000, "Commit time out");
    } while ((!Verilated::gotFinish()) && cycle < MAX_CYCLE);
}
int parse_args(int argc, char *argv[]);

int main(int argc, char *argv[])
{
    parse_args(argc, argv);
    char temp_str[128];
    sprintf(temp_str, "%s/build/riscv64-nemu-interpreter-so", getenv("NEMU_HOME"));
    dut_difftest_init(temp_str);
    srand(0);
    Verilated::randSeed(0);
    Verilated::randReset(0);
    top = new Vsoc();
#if TRACE
    Verilated::traceEverOn(true);
    tfp = new VerilatedFstC();
    top->trace(tfp, 0);
    tfp->open("Vsoc.fst");
#endif
    reset();
    uint64_t run_time = get_time_us();
    soc_test();
    run_time = get_time_us() - run_time;
    LOG("simulation speed: %.02f KHz\n", (float)(cycle * 1000) / run_time);

    // Final model cleanup
    top->final();

#if TRACE
    tfp->close();
    delete tfp;
#endif
    delete top;
    Counter::print_counters();
    LOG("All test done");
    float ipc = (float)total_inst / cycle;
    printf(COLOR("IPC : %.03f\n", GREEN), ipc);
    if (Verilated::gotError())
        return -1;
    return 0;
}
